﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Platformer_Example.Controller.Data;
using Platformer_Example.Controller.Network.Messages;
using Transformable_Engine_v2.Engine.Transformable_Math.Geometry;

namespace Platformer_Example.Controller.Network
{
    public class ClientSummaryData
    {
        public IPAddress Ip { get; set; }
        public string Name { get; set; }
        public int Team { get; set; }
        public Guid Id { get; set; }
        public bool IsLoaded { get; set; }
    }

    public class ServerData
    {
        public ServerData()
        {
            Clients = new Dictionary<Guid, ClientSummaryData>();
        }


        public string GameName { get; set; }

        private MapSummary _summary;
        public MapSummary MapSummary
        {
            get { return _summary; }
            set 
            { 
                _summary = value;
                ClientTeamAssociation = new ClientSummaryData[_summary.Teams, _summary.PlayersPerTeam];
                Teams = Team.GetRandomTeams(_summary.Teams);
            }
        }

        public bool HasAnySlotLeft()
        {
            return FindEmptyPlayerSlot() != null;
        }

        public Guid AddPlayer(string playerName, IPAddress ipAddress)
        {
            TE_Vector2 slot = FindEmptyPlayerSlot();

            Guid g = Guid.NewGuid();
            ClientSummaryData client = new ClientSummaryData
                                           {
                                               Ip = ipAddress,
                                               Name = playerName,
                                               Team = (int) slot.X,
                                               Id = g,
                                           };
            Clients.Add(g, client);
            ClientTeamAssociation[(int) slot.X, (int) slot.Y] = client;

            return g;
        }

        TE_Vector2 FindEmptyPlayerSlot()
        {
            for (int i = 0; i < ClientTeamAssociation.GetLength(0); i++)
            {
                int emptySlotId = FindEmptyPlayerSlot(i);
                if(emptySlotId != -1)
                    return new TE_Vector2(i, emptySlotId);
            }

            //No empty slot found
            return null;
        }

        int FindEmptyPlayerSlot(int teamId)
        {
            for (int j = 0; j < ClientTeamAssociation.GetLength(1); j++)
            {
                if (ClientTeamAssociation[teamId, j] == null)
                    return j;
            }

            return -1;
        }

        public Dictionary<Guid, ClientSummaryData> Clients { get; private set; }
        public ClientSummaryData[,] ClientTeamAssociation { get; private set; }
        public Team[] Teams { get; private set; }
        public Guid LocalPlayer { get; set; }

        public string[] GetTeamNamesList()
        {
            return Teams.Select(x => x.Name).ToArray();
        }

        public string[] GetPlayerNamesList()
        {
            return ClientTeamAssociation.Cast<ClientSummaryData>().Select(x => x == null ? "Empty" : x.Name).ToArray();
        }

        public void PrintClientTeamAssociation()
        {
            for (int i = 0; i < Teams.Length; i++)
            {
                Console.WriteLine("Team #{0} - {1}", i, Teams[i].Name);

                for (int j = 0; j < ClientTeamAssociation.GetLength(1); j++)
                {
                    if(ClientTeamAssociation[i, j] == null)
                        Console.WriteLine("     Empty");
                    else
                        Console.WriteLine("     {0} [{1}]", ClientTeamAssociation[i, j].Name, ClientTeamAssociation[i, j].Id);
                }
            }
        }

        public IPAddress[] ClientAddresses()
        {
            return Clients.Select(x => x.Value.Ip).Where(x => x != null).ToArray();
        }

        public IPAddress[] ClientAddressesBut(Guid guid)
        {
            return Clients.Where(x => x.Value.Id != guid).Select(x => x.Value.Ip).Where(x => x != null).ToArray();
        }

        public IPAddress ClientAddress(Guid guid)
        {
            return Clients[guid].Ip;
        }

        public PlayerData[] GetPlayers()
        {
            return ClientTeamAssociation.Cast<ClientSummaryData>().Select(x =>
                                                                              {
                                                                                  if (x == null)
                                                                                  {
                                                                                      return new PlayerData
                                                                                                 {
                                                                                                     Id = "Empty",
                                                                                                     Name = "",
                                                                                                 };
                                                                                  }
                                                                                  else
                                                                                  {
                                                                                      return new PlayerData
                                                                                                 {
                                                                                                     Id = x.Id.ToString(),
                                                                                                     Name = x.Name,
                                                                                                 };
                                                                                  }
                                                                              }).ToArray();
        }

        public bool LoadingDone(Guid id)
        {
            Clients[id].IsLoaded = true;

            return Clients.All(x => x.Value.IsLoaded);
        }
    }
}